// 定义存储值的类型约束（仅允许可序列化的数据类型）
type StorageValue = string | number | boolean | object | null;

// 错误类型定义
enum StorageErrorType {
  Unavailable = 'STORAGE_UNAVAILABLE',
  Serialization = 'SERIALIZATION_ERROR',
  QuotaExceeded = 'QUOTA_EXCEEDED',
  NotFound = 'NOT_FOUND'
}

class StorageError extends Error {
  constructor(public type: StorageErrorType, message: string) {
    super(message);
    this.name = 'StorageError';
  }
}

export default class SessionStorage {
  /**
   * 检测 sessionStorage 是否可用
   */
  private static isAvailable(): boolean {
    try {
      const testKey = '__test__';
      sessionStorage.setItem(testKey, testKey);
      sessionStorage.removeItem(testKey);
      return true;
    } catch (e) {
      return false;
    }
  }

  /**
   * 创建/更新存储项
   * @param key 键名
   * @param value 存储值
   * @throws {StorageError} 存储失败时抛出错误
   */
  static set<T extends StorageValue>(key: string, value: T): void {
    if (!this.isAvailable()) {
      throw new StorageError(
        StorageErrorType.Unavailable,
        'sessionStorage is not available'
      );
    }

    try {
      const serialized = JSON.stringify(value);
      sessionStorage.setItem(key, serialized);
    } catch (error) {
      if (error instanceof DOMException && error.name === 'QuotaExceededError') {
        throw new StorageError(
          StorageErrorType.QuotaExceeded,
          `Storage quota exceeded for key: ${key}`
        );
      }
      throw new StorageError(
        StorageErrorType.Serialization,
        `Failed to serialize value for key: ${key}`
      );
    }
  }

  /**
   * 读取存储项
   * @param key 键名
   * @returns 解析后的值或 undefined（当不存在时）
   * @throws {StorageError} 反序列化失败时抛出错误
   */
  static get<T extends StorageValue>(key: string): T | undefined {
    if (!this.isAvailable()) return undefined;

    const serialized = sessionStorage.getItem(key);
    if (serialized === null) return undefined;

    try {
      return JSON.parse(serialized) as T;
    } catch (error) {
      throw new StorageError(
        StorageErrorType.Serialization,
        `Failed to parse stored value for key: ${key}`
      );
    }
  }

  /**
   * 更新现有项（必须已存在）
   * @param key 键名
   * @param value 新值
   * @throws {StorageError} 当键不存在或更新失败时抛出
   */
  static update<T extends StorageValue>(key: string, value: T): void {
    if (this.get(key) === undefined) {
      throw new StorageError(
        StorageErrorType.NotFound,
        `Key not found: ${key}`
      );
    }
    this.set(key, value);
  }

  /**
   * 删除存储项
   * @param key 键名
   */
  static delete(key: string): void {
    if (!this.isAvailable()) return;
    sessionStorage.removeItem(key);
  }

  /**
   * 清空所有存储项
   */
  static clear(): void {
    if (!this.isAvailable()) return;
    sessionStorage.clear();
  }

  /**
   * 获取所有存储键值对
   * @returns 包含所有数据的对象
   */
  static getAllItems(): Record<string, unknown> {
    if (!this.isAvailable()) return {};

    return Object.keys(sessionStorage).reduce((acc, key) => {
      try {
        acc[key] = this.get(key);
      } catch {
        // 跳过无法解析的数据
      }
      return acc;
    }, {} as Record<string, unknown>);
  }
}